﻿namespace Digitalmes.Extensions
{
    using Digitalmes.Configuration;
    using Digitalmes.Services.DbFactory;
    using Digitalmes.Services.Hosted;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using MQTTnet.AspNetCore;
    using System;
    using System.Collections.Generic;
    using System.Reflection;

    /// <summary>
    /// Defines the <see cref="ServiceCollectionExtension" />
    /// </summary>
    public static class ServiceCollectionExtension
    {
        /// <summary>
        /// The AddDbContextFactory
        /// </summary>
        /// <param name="services">The services<see cref="IServiceCollection"/></param>
        /// <param name="configuration">The configuration<see cref="IConfiguration"/></param>
        public static void AddDbContextFactory(this IServiceCollection services, IConfiguration configuration)
        {
            // 注册工厂
            services.AddScoped<IDbContextFactory, DbContextFactory>();
        }

        /// <summary>
        /// The AddMeService
        /// </summary>
        /// <param name="services">The services<see cref="IServiceCollection"/></param>
        /// <param name="configuration">The configuration<see cref="IConfiguration"/></param>
        public static void AddMesService(this IServiceCollection services, IConfiguration configuration)
        {
            var ass = AppDomain.CurrentDomain.GetAssemblies()
             .Where(x => x.FullName.Contains("Digitalmes") &&
                    !x.FullName.Contains("Elsa.Core"))
             .ToList();

            services.RegisterSingleton(ass);
            services.RegisterTransient(ass);
            services.RegisterScoped(ass);

            // 配置MQTT设置
            services.Configure<MqttSettings>(configuration.GetSection("MqttSettings"));

            //注册批量服务
            services.AddSingleton<BatchDataService>();
            services.AddHostedService<BatchDataService>();

            // 注册MQTT服务器服务

            services.AddHostedMqttServer(
                optionsBuilder =>
                {
                    optionsBuilder.WithDefaultEndpoint();
                });

            services.AddMqttConnectionHandler();
            services.AddConnections();

            services.AddSingleton<MqttController>();
            services.AddSingleton<IMQTT>((s)=> CommonServiceLocator.ServiceLocator.Current.GetService<MqttController>());
           
        }

        /// <summary>
        /// The RegisterTransient
        /// </summary>
        /// <param name="services">The services<see cref="IServiceCollection"/></param>
        /// <param name="ass">The ass<see cref="List{Assembly}"/></param>
        private static void RegisterTransient(this IServiceCollection services, List<Assembly> ass)
        {
            var transients = ass.SelectMany(a => a.GetTypes())

              .Where(t => !t.IsAbstract && t.GetInterfaces()
              .Any(i => i == typeof(ITransient))).ToList();
            foreach (var tran in transients)
            {
                var interfaces = tran.GetInterfaces().Where(x => x.Name.Contains(tran.Name)).ToList();

                if (interfaces.Any() && interfaces.Count == 1)
                {
                    services.AddTransient(interfaces[0], tran);
                }
                else
                {
                    services.AddTransient(tran);
                }
            }
        }

        /// <summary>
        /// The RegisterScoped
        /// </summary>
        /// <param name="services">The services<see cref="IServiceCollection"/></param>
        /// <param name="ass">The ass<see cref="List{Assembly}"/></param>
        private static void RegisterScoped(this IServiceCollection services, List<Assembly> ass)
        {
            var scops = ass.SelectMany(a => a.GetTypes())

              .Where(t => !t.IsAbstract && t.GetInterfaces()
              .Any(i => i == typeof(IScoped))).ToList();
            foreach (var scop in scops)
            {
                var interfaces = scop.GetInterfaces().Where(x => x.Name.Contains(scop.Name)).ToList();

                if (interfaces.Any() && interfaces.Count == 1)
                {
                    services.AddScoped(interfaces[0], scop);
                }
                else
                {
                    services.AddScoped(scop);
                }
            }
        }

        /// <summary>
        /// The RegisterSingleton
        /// </summary>
        /// <param name="services">The services<see cref="IServiceCollection"/></param>
        /// <param name="ass">The ass<see cref="List{Assembly}"/></param>
        private static void RegisterSingleton(this IServiceCollection services, List<Assembly> ass)
        {
            var singlets = ass.SelectMany(a => a.GetTypes())

                          .Where(t => !t.IsAbstract && t.GetInterfaces()
                          .Any(i => i == typeof(ISingleton))).ToList();
            foreach (var sing in singlets)
            {
                var interfaces = sing.GetInterfaces().Where(x => x.Name.Contains(sing.Name)).ToList();

                if (interfaces.Any() && interfaces.Count == 1)
                {
                    services.AddSingleton(interfaces[0], sing);
                }
                else
                {
                    services.AddSingleton(sing);
                }
            }
        }
    }
}
